package cn.ztydata.teachingsystem.heaven.web.wrapper;

import cn.ztydata.teachingsystem.heaven.service.SessionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionContext;
import java.util.*;

/**
 * Created by kazaff on 2014/12/5.
 */
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class CustomHttpSession implements CustomSession {

    private final static Logger log = LoggerFactory.getLogger(CustomHttpSession.class);

    private String sessionId = null;
    private Map<String, Object> data = null;
    private long creationTime = 0;

    @Value("${session.MaxInactiveInterval}")
    private int MaxInactiveInterval;

    @Autowired
    private SessionService sessionService;

    private ServletContext servletContext;

    private boolean isChange = false;   //是否修改标志位，用于判断是否需要回写持久层

    /**
     * init方法和下面的setServletContext方法都为初始化该bean的方法，之所以分成2步，是因为servletContext在Filter中可以获得
     * 而sessionId在Interceptor中可以获得（文件上传类型），这就导致该bean的初始化工作需要格外注意！
     * @param sessionId
     */
    public void init(String sessionId){
        this.sessionId = sessionId;
    }

    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    /**
     *  todo
     *  springMVC的DispatcherServlet会默认启动SessionFlashMapManager，而这个类会首先调用一次我们定义的HttpSessionProxy，
     *  从而导致首次调用时并没有初始化sessionId属性，目前没有找到禁用springMVC该机制的方式
     *  @return
     */
    private boolean checkSessionId(){

       return this.sessionId != null;
    }

    @Override
    public Object getAttribute(String name){

        if(!this.checkSessionId()){
            return null;
        }

        if(this.data == null){
            //去持久层中获取对应的会话信息
            this.data = sessionService.getData(this.sessionId);

            if(this.data == null) {
                this.data = new HashMap<String, Object>();
            }
        }

        return this.data.get(name);
    }

    @Override
    public Enumeration<String> getAttributeNames(){
        return Collections.enumeration(data.keySet());
    }

    @Override
    public String getId(){
        return this.sessionId;
    }

    @Override
    public long getCreationTime(){
        //检查给定的sessionId是否已经过期
        Long restTime = sessionService.getTTL(this.sessionId);
        if(restTime < 0){
            return restTime;
        }

        //如果曾经已经获取过，则直接返回
        if(this.creationTime == 0){
            //当前时间-(有效期-剩余时间)
            this.creationTime = System.currentTimeMillis() - MaxInactiveInterval*1000 + restTime;
        }

        return this.creationTime;
    }

    @Override
    public int getMaxInactiveInterval(){
        return this.MaxInactiveInterval;
    }

    @Override
    public long getLastAccessedTime(){
        return this.getCreationTime();
    }

    @Override
    public ServletContext getServletContext(){
        return this.servletContext;
    }

    @Override
    public HttpSessionContext getSessionContext(){
        return null;
    }

    @Override
    public Object getValue(String name){
        return this.getAttribute(name);
    }

    @Override
    public String[] getValueNames(){
        Set<String> names = data.keySet();
        return names.toArray(new String[names.size()]);
    }

    @Override
    public void invalidate(){
        this.data = null;
        this.servletContext = null;
        this.sessionId = null;
        this.creationTime = 0;
    }

    @Override
    public boolean isNew(){
        return true;
    }

    @Override
    public void putValue(String name, Object value){
        this.setAttribute(name, value);
    }

    @Override
    public void setAttribute(String name, Object value){

        if(this.data == null){
            //去持久层中获取对应的会话信息
            this.data = sessionService.getData(this.sessionId);
            if(this.data == null) {
                this.data = new HashMap<String, Object>();
            }
        }

        this.isChange = true;
        this.data.put(name, value);
    }

    @Override
    public void removeValue(String name){
        this.removeAttribute(name);
    }

    @Override
    public void removeAttribute(String name){
        if(this.data.containsKey(name)){
            this.isChange = true;
            this.data.remove(name);
        }
    }

    @Override
    public void setMaxInactiveInterval(int internal){
        this.MaxInactiveInterval = internal;
    }

    /**
     * 用于把会话数据回写到持久层
     */
    public void save(){
        //把会话数据回写到持久层
        if(this.isChange){
            sessionService.saveData(this.sessionId, this.data);
        }
    }
}
